#include <gwbase/base/logging.h>
#include "dicom/gateway.h"
#include "dicom/sync_manager.h"
#include "dicom/session.h"
#include "dicom/dicom_conf.h"
#include "dicom/recovery/recovery.h"
#include "dicom/recovery/recovery.h"
#include <getopt.h>
#include <sys/resource.h>

#include "version.h"

using namespace dicom;

static struct option long_options[] = {{"version", no_argument, 0, 'v'},
                                       {"help", no_argument, 0, 'h'},
                                       {"conf", required_argument, 0, 'c'},
                                       {"debug", no_argument, 0, 'd'},
                                       {0, 0, 0, 0}};

struct RecoveryArgs {
  bool show_help;
  bool show_version;
  bool debug;
  std::string conf_file;
  std::string user;
  std::string password;

  RecoveryArgs()
      : show_help(false),
        show_version(false),
        debug(false),
        conf_file("dicom.conf") {}

  bool TryParseOption(int argc, char** argv) {
    int c;
    while (true) {
      int option_index = 0;
      c = ::getopt_long(argc, argv, "vhc:du:p:", long_options, &option_index);
      if (c == -1) break;

      switch (c) {
        case 'v':
          this->show_version = true;
          break;
        case 'h':
          this->show_help = true;
          break;
        case 'c':
          this->conf_file = optarg;
          break;
        case 'u':
          this->user = optarg;
          break;
        case 'p':
          this->password = optarg;
          break;
        case 'd':
          this->debug = true;
          break;
        default:
          return false;
      }
    }
    return true;
  }
};

static void ShowVersion() {
  printf("SurCloud Gateway Recovery Tool (%s)\n", VERSION);
  printf("  Git Revision:   %s\n", GIT_SHA1);
  printf("  Cloud Backend:  %s\n", BACKEND);
}

static void ShowHelp() {
  printf("SurCloud Gateway Recveroy Tool Version: %s\n", VERSION);
  printf("Usage\n");
  printf("  dicom_recovery [-v] [-h] [-d] [-c <conf_file>]\n");
  printf("Options\n");
  printf("  -v, --version  show version\n");
  printf("  -h, --help     show this help\n");
  printf(
      "  -c, --conf <conf_file>  use this config file, default is "
      "'dicom.conf'\n");
  printf("  -u, --user     user name\n");
  printf("  -p, --passowrd user's password\n");
  printf("  -d, --debug    enable debug log\n");
}

int Main(void* arg) {
  Status s;
  RecoveryArgs* ra = static_cast<RecoveryArgs*>(arg);
  if (ra == NULL) abort();

  if (ra->debug) {
    dicom::SetLogLevel(dicom::LogLevel::kLogTrace);
  }

  std::string conf_file = ra->conf_file;
  std::shared_ptr<DicomConf> conf(DicomConf::LoadConfFile(conf_file));
  if (conf.get() == NULL) {
    fprintf(stderr, "failed to parse config\n");
    return -1;
  }

  std::string dbdir = conf->GetDbDir();
  s = dicom::CreateDirRecurisve(dbdir);
  if (!s.ok()) {
    fprintf(stderr, "Failed to create dir: %s\n", dbdir.c_str());
    return -1;
  }

  if (DoRecovery(conf.get(), ra->user, ra->password) == false) {
    fprintf(stderr, "Failed to recover\n");
    return -1;
  }

  fprintf(stderr, "Recover successfully\n");
  return 0;
}

static void EnableCoreDump() {
  // core dumps may be disallowed by parent of this process; change that
  struct rlimit core_limits;
  core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
  setrlimit(RLIMIT_CORE, &core_limits);
}

int main(int argc, char** argv) {
  EnableCoreDump();

  RecoveryArgs ra;
  if (ra.TryParseOption(argc, argv) == false) {
    return -1;
  }

  if (ra.show_help) {
    ShowHelp();
    return 0;
  }

  if (ra.show_version) {
    ShowVersion();
    return 0;
  }

  if (ra.user.empty() || ra.password.empty()) {
    ShowHelp();
    return 0;
  }

  return Main(&ra);
}
